package com.gzk.user.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.gzk.basic.constant.BaseConstant;
import com.gzk.basic.exception.BusinessException;
import com.gzk.basic.util.AjaxResult;
import com.gzk.basic.util.HttpClientUtils;
import com.gzk.basic.util.MD5Utils;
import com.gzk.basic.util.StrUtils;
import com.gzk.user.domain.Logininfo;
import com.gzk.user.domain.User;
import com.gzk.user.domain.WxUser;
import com.gzk.user.dto.LoginDto;
import com.gzk.user.mapper.LogininfoMapper;
import com.gzk.user.mapper.UserMapper;
import com.gzk.user.mapper.WxUserMapper;
import com.gzk.user.service.ILoginService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements ILoginService {

    @Autowired
    private LogininfoMapper logininfoMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private WxUserMapper wxUserMapper;

    @Override
    public Map<String, Object> login(LoginDto dto) {
        //判断是否为空
        if(StringUtils.isEmpty(dto.getUsername())||StringUtils.isEmpty(dto.getPassword())){
            throw new BusinessException("用户名或者密码为空！！！");
        }


        //判断用户是否存在
        Logininfo logininfo = logininfoMapper.loadByUsername(dto);
        if (logininfo == null){
            throw new BusinessException("用户不存在！！");
        }

        //校验密码
        String md5Pwd = logininfo.getPassword();
        String pwd = MD5Utils.encrypByMd5(dto.getPassword() + logininfo.getSalt());
        if(!pwd.equals(md5Pwd)){
            throw new BusinessException("密码错误！！！");
        }

        //密码正确，存入redis
        //获取token
        Map<String, Object> map = loginNoPwd(logininfo);
        return map;
    }

    @Override
    public AjaxResult wechat(Map<String, String> map) {
        //获取url
        String getTokenURL = BaseConstant.GET_TOKEN_URL
                .replace("APPID", BaseConstant.APPID)
                .replace("SECRET", BaseConstant.SECRET)
                .replace("CODE", map.get("code"));

        //发送请求
        String s = HttpClientUtils.httpGet(getTokenURL);
        //转换
        JSONObject jsonObject = JSONObject.parseObject(s);
        //获取token
        String accessToken = jsonObject.getString("access_token");
        //获取openid
        String openId = jsonObject.getString("openid");

        //根据openId查询t_wxuser
        WxUser wxUser = wxUserMapper.loadByOpenId(openId);
        //判断有没有值
        if(wxUser != null && wxUser.getUser_id()!=null){
            //登陆过了放行
            //logininfo信息
            Logininfo logininfo = logininfoMapper.loadByUserId(wxUser.getUser_id());
            //免密登录
            Map<String, Object> map1 = loginNoPwd(logininfo);
            return AjaxResult.ok().setResultObj(map1);
        }else{
            //没有登陆过，返回token和openid给前端
            String binderParam = "?accessToken=" + accessToken + "&openId=" + openId;
            return AjaxResult.ok().setSuccess(false).setResultObj(binderParam);
        }
    }

    @Override
    public Map<String, Object> binder(Map<String, String> map) {
        //非空判断
        String phone = map.get("phone");
        String verifyCode = map.get("verifyCode");
        String accessToken = map.get("accessToken");
        String openId = map.get("openId");
        //非空判断
        if(
                StringUtils.isEmpty(phone)||
                StringUtils.isEmpty(verifyCode)||
                StringUtils.isEmpty(accessToken)||
                StringUtils.isEmpty(openId)
                ){
            throw new BusinessException("参数不能为空！！");
        }

        //比对验证码
        String codeVal = (String)redisTemplate.opsForValue().get(BaseConstant.BUSINESS_BINDER_PREFIX + phone);

        if(StringUtils.isEmpty(codeVal)){
            throw new BusinessException("验证码已过期，请重新获取！");
        }
        String code = codeVal.split(":")[0];

        if(!code.equalsIgnoreCase(verifyCode)){
            throw new BusinessException("验证码不正确！！！");
        }

        //连表查询，去除脏数据，查询手机号是否存在
        User user = userMapper.loadByPhone(phone);
        Logininfo logininfo = null;
        if(user != null){
            //查询出logininfo
            logininfo = logininfoMapper.loadByUserId(user.getId());
        }else {
            //创建一个新用户
            user = initUser(phone);
            logininfo = user2Logininfo(user);
            //存入logininfo
            logininfoMapper.save(logininfo);
            user.setLogininfo_id(logininfo.getId());
            //存入user
            userMapper.save(user);
        }

        //发送请求去微信端拿用户资源
        String wxUserTxt = HttpClientUtils.httpGet(BaseConstant.GET_WXUSER_URL
                .replace("ACCESS_TOKEN", accessToken)
                .replace("OPENID", openId)
        );

        //转换
        WxUser wxUser = JSONObject.parseObject(wxUserTxt, WxUser.class);
        wxUser.setUser_id(user.getId());

        //存数据库
        wxUserMapper.save(wxUser);

        //免密登录
        Map<String, Object> map1 = loginNoPwd(logininfo);


        return map1;
    }

    private Logininfo user2Logininfo(User user) {
        Logininfo logininfo = new Logininfo();
        BeanUtils.copyProperties(user, logininfo);
        return logininfo;
    }

    /**
     * 初始化用户
     * @param phone
     * @return
     */
    private User initUser(String phone) {
        User user = new User();
        user.setUsername(phone);
        user.setPhone(phone);

        String salt = StrUtils.getComplexRandomString(32);
        //加密加盐
        String password = MD5Utils.encrypByMd5("123" + salt);

        //发短信提示用户密码为123

        user.setSalt(salt);
        user.setPassword(password);
        return user;
    }

    /**
     * 免密登录
     */
    private Map<String,Object> loginNoPwd(Logininfo logininfo){
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(token, logininfo, 30, TimeUnit.MINUTES);

        //返回map
        Map<String, Object> map = new HashMap<>();

        map.put("token", token);

        logininfo.setSalt(null);
        logininfo.setPassword(null);
        map.put("logininfo", logininfo);
        return map;
    }
}
